/* TCSS 590A - Cybernetics and Systems
 * Group Project - Modeling
 * By Barry Jones, Naren Meadem, Michael Pitts, Yuan Tao
 * Fall 2012, University of Washington, Tacoma
 */
package model.delayed;


/**
 * An Account that stores money.  It may generate interest and grow on its own, and 
 * it may also have transfers delayed.
 * @author Michael Pitts
 * @version Nov 26, 2012
 */
public class BasicAccount implements Account
{
	/** The rate of growth per unit time.*/
	private final double my_rate;
	
	/** Used to generate the delay for actions.*/
	private final Generator my_generator;
	
	/** The fractional value of this savingsAccount, should be less than one.*/
	private double my_fraction;
	
	/** The current value of this savingsAccount.*/
	private long my_value;
	
	/**
	 * Creates a new BasicAccount
	 * @param the_value is the starting value of the BasicAccount.
	 * @param the_rate is the interest rate for the BasicAccount.
	 * @param the_generator is the generator for the timing between transfer events.  
	 * If null, transfer events will have no delay.
	 */
	public BasicAccount(final long the_value, final double the_rate, 
			final Generator the_generator)
	{
		my_rate = the_rate;
		my_fraction = 0.0;
		my_value = the_value;
		my_generator = the_generator;
	}
	
	/**
	 * Generates an BasicAccount with no delay.
	 * @param the_value is the starting value of the BasicAccount.
	 * @param the_rate is the interest rate of the BasicAccount.
	 */
	public BasicAccount (final long the_value, final double the_rate)
	{
		this(the_value, the_rate, null);
	}
	
	/**
	 * Creates an BasicAccount with no interest and no delay.
	 * @param the_value is the starting value of the BasicAccount.
	 */
	public BasicAccount(final long the_value)
	{
		this(the_value, 0.0, null);
	}
	
	public long getValue() {return my_value;}

	public void changeValue(final long the_value) {my_value += the_value;}

	public Event deposit(final long the_value, final long the_time) 
	{
		return new Event(the_value, the_time, this);
	}

	public Event withdraw(final long the_value, final long the_time)
	{
		if (my_generator == null) return new Event(the_value, the_time, this);
		return new Event(the_value, the_time + my_generator.delay(the_time), this);
	}
	
	public double getRate() {return my_rate;}
	
	/**
	 * Gets the current fractional value of the account.
	 * @return a number representing the fractional progress of the 
	 * value towards the next whole number.
	 */
	public double getFraction() {return my_fraction;}
	
	/**
	 * Changes the fractional value of this Account.
	 * @param the_value is the value to change the Account by.
	 */
	public void changeFraction(final double the_value) {my_fraction += the_value;}
	
	public void addInterest()
	{
		final double interest = my_rate * (getValue() + my_fraction);
		changeValue((long) interest);
		my_fraction += (interest - (long)interest);
		if (my_fraction >= 1) {
			changeValue((long) my_fraction);
			my_fraction -= (long) my_fraction;
		}
	}

	@Override public boolean inLegalState()
	{
		return getValue() > -1;
	}
}
